﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ApplicationServer.Caching.AdminApi;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using AppfabricAdministrator.Entities;
using AppfabricAdministrator.Entities.Interface;

namespace AppfabricAdministrator.Commands
{
    public class PowershellCommands
    {
        public AdminEntity adminEntity=null;
        public Message Message = null;
        private Runspace rs = null;

        public void CreateRunSpace()
        {
            var state = InitialSessionState.CreateDefault();
            state.ImportPSModule(new string[] { "DistributedCacheAdministration", "DistributedCacheConfiguration" });
            state.ThrowOnRunspaceOpenError = true;
            rs = RunspaceFactory.CreateRunspace(state);
            rs.Open();
        }

        public PowershellCommands(String _provider, String _connectionString)
        {
            if (rs == null)
                CreateRunSpace();
            Cluster.UseCluster clusterCommand = new Cluster.UseCluster();
            clusterCommand.Parameters["Provider"] = _provider;
            clusterCommand.Parameters["ConnectionString"] = _connectionString;
            InvokeCommand(clusterCommand);
            adminEntity = new AdminEntity();
        }

        public PowershellCommands()
        {
            Message = new Message();
        }

        public PowershellCommands(Cluster.UseCluster clusterCommand)
        {
            if (rs == null)
                CreateRunSpace();

            InvokeCommand(clusterCommand);
            adminEntity = new AdminEntity();
        }

        public void InvokeGC()
        {
            Cluster.InvokeGC clusterCommand = new Cluster.InvokeGC();
            InvokeCommand(clusterCommand);
        }
        /// <summary>
        /// Invokes a command object that implements ICommand
        /// </summary>
        /// <param name="commandObject"></param>
        /// <returns></returns>
        public Collection<PSObject> InvokeCommand(ICommand commandObject)
        {
            System.Windows.Input.Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
            var pipe = rs.CreatePipeline();
            Collection<PSObject> output = null;

            var cmd = new Command(commandObject.CommandName);
            if (commandObject.Parameters != null)
            {
                foreach (KeyValuePair<String, Object> param in commandObject.Parameters)
                {
                    if (param.Value == null)
                        continue;
                    cmd.Parameters.Add(new CommandParameter(param.Key, param.Value));
                }
            }
            pipe.Commands.Add(cmd);
            try
            {
                output = pipe.Invoke();
                if (Message != null)
                    this.Message.SetMessage(commandObject.SuccessMessage);
                return output;
            }
            catch (Exception ex)
            {
                if (Message != null)
                {
                    Message.SetMessage(ex.Message, MessageType.Error);
                }
                return null;
            }
            finally
            {
                System.Windows.Input.Mouse.OverrideCursor = System.Windows.Input.Cursors.Arrow;
            }
        }

        public void SetSecurity(Cluster.ClusterSecurity clusterCommand)
        {
            InvokeCommand(clusterCommand);
        }

        public void GrantAccess(String _clientAccount)
        {
            Cluster.GrantAccess clusterCommand = new Cluster.GrantAccess();
            clusterCommand.Parameters["Account"] = _clientAccount;
            InvokeCommand(clusterCommand);
        }

        public void RevokeAccess(String _clientAccount)
        {
            Cluster.RevokeAccess clusterCommand = new Cluster.RevokeAccess();
            clusterCommand.Parameters["Account"] = _clientAccount;
            InvokeCommand(clusterCommand);
        }

        public List<String> GetAllowedAccounts()
        {
            Cluster.GetClientAccounts clusterCommand = new Cluster.GetClientAccounts();
            var result=InvokeCommand(clusterCommand);
            if (result != null && result.Count!=0)
            {
                return (from o in result
                        select o.ToString()).ToList<String>();
            }
            return null;
        }

        public void GetCacheHosts()
        {
            adminEntity.Hosts = new List<HostInfo>();
            Host.GetCacheHost hostCommand = new Host.GetCacheHost();
            var output = InvokeCommand(hostCommand);
            if (output != null)
            {
                foreach (PSObject o in output)
                {
                    var hostObject = o.BaseObject as HostInfo;
                    adminEntity.Hosts.Add(hostObject);
                }
            }
        }

        public void GetCache()
        {
            adminEntity.Cache = new List<CacheInfo>();
            Cache.GetCache cacheCommand = new Cache.GetCache();
            var output = InvokeCommand(cacheCommand);
            if (output != null)
            {
                foreach (PSObject o in output)
                {
                    var cacheObject = o.BaseObject as CacheInfo;
                    adminEntity.Cache.Add(cacheObject);
                }
            }
        }

        public void SetHostConfig(HostConfig _config)
        {
            Host.GetCacheHostConfig hostCommand = new Host.GetCacheHostConfig();
            hostCommand.IsSave = true;
            hostCommand.CommandName = "Set-CacheHostConfig";
            hostCommand.Parameters["ArbitrationPortNumber"] = _config.ArbitrationPortNumber;
            hostCommand.Parameters["CachePort"] = _config.CachePort;
            hostCommand.Parameters["CacheSize"] = _config.CacheSize;
            hostCommand.Parameters["ClusterPortNumber"] = _config.ClusterPortNumber;
            hostCommand.Parameters["HighWatermark"] = _config.HighWatermark;
            hostCommand.Parameters["LowWatermark"] = _config.LowWatermark;
            hostCommand.Parameters["HostName"] = _config.HostName;
            hostCommand.Parameters["IsLeadHost"] = _config.IsLeadHost;
            hostCommand.Parameters["RefreshNow"] = _config.RefreshNow;
            hostCommand.Parameters["ReplicationPortNumber"] = _config.ReplicationPortNumber;
            InvokeCommand(hostCommand);
        }

        public HostConfig GetHostConfig(String _hostName, Int32 _portNo)
        {
            Host.GetCacheHostConfig hostCommand = new Host.GetCacheHostConfig();
            hostCommand.Parameters["HostName"] = _hostName;
            hostCommand.Parameters["CachePort"] = _portNo;
            var output= InvokeCommand(hostCommand);
            if (output != null)
            {
                var config = new HostConfig();
                config.HostName = _hostName;
                foreach (PSObject o in output)
                {
                    foreach (PSPropertyInfo psPropertyInfo in o.Properties)
                    {

                        if (psPropertyInfo.Name == "ArbitrationPort")
                        {
                            config.ArbitrationPortNumber = Convert.ToInt32(psPropertyInfo.Value);
                            continue;
                        }
                        else if (psPropertyInfo.Name == "CachePort")
                        {
                            config.CachePort = Convert.ToInt32(psPropertyInfo.Value);
                            continue;
                        }
                        else if (psPropertyInfo.Name == "Size")
                        {
                            config.CacheSize = Convert.ToInt64(psPropertyInfo.Value);
                            continue;
                        }
                        else if (psPropertyInfo.Name == "ClusterPort")
                        {
                            config.ClusterPortNumber = Convert.ToInt32(psPropertyInfo.Value);
                            continue;
                        }
                        else if (psPropertyInfo.Name == "HighWatermark")
                        {
                            config.HighWatermark = Convert.ToInt32(psPropertyInfo.Value);
                            continue;
                        }
                        else if (psPropertyInfo.Name == "IsLeadHost")
                        {
                            config.IsLeadHost = psPropertyInfo.Value.ToString();
                            continue;
                        }
                        else if (psPropertyInfo.Name == "LowWatermark")
                        {
                            config.LowWatermark = Convert.ToInt32(psPropertyInfo.Value);
                            continue;
                        }
                        else if (psPropertyInfo.Name == "ServiceName")
                        {
                            config.ServiceName = psPropertyInfo.Value.ToString();
                            continue;
                        }
                        else if (psPropertyInfo.Name == "ReplicationPort")
                        {
                            config.ReplicationPortNumber = Convert.ToInt32(psPropertyInfo.Value);
                            continue;
                        }
                    }
                }
                return config;
            }
            return null;
        }

        public CacheConfig GetCacheConfig(String _cacheName)
        {
            Cache.GetCacheConfig cacheCommand = new Cache.GetCacheConfig();
            cacheCommand.Parameters["CacheName"] = _cacheName;
            var output = InvokeCommand(cacheCommand);
            if (output != null)
            {
                var config = new CacheConfig();
                config.CacheName = _cacheName;
                foreach (PSObject o in output)
                {
                    foreach (PSPropertyInfo psPropertyInfo in o.Properties)
                    {
                        if (psPropertyInfo.Name == "TimeToLive")
                        {
                            config.TimeToLive = psPropertyInfo.Value.ToString();
                            continue;
                        }
                        else if (psPropertyInfo.Name == "Secondaries")
                        {
                            config.Secondaries = psPropertyInfo.Value.ToString() == "0" ? false : true;
                            continue;
                        }
                        else if (psPropertyInfo.Name == "MinSecondaries")
                        {
                            config.MinSecondaries = psPropertyInfo.Value.ToString() == "0" ? false : true;
                            continue;
                        }
                        else if (psPropertyInfo.Name == "IsExpirable")
                        {
                            config.Expirable = psPropertyInfo.Value.ToString() == "True" ? true : false;
                            continue;
                        }
                        else if (psPropertyInfo.Name == "EvictionType")
                        {
                            config.Eviction = psPropertyInfo.Value.ToString();
                            continue;
                        }
                        else if (psPropertyInfo.Name == "NotificationsEnabled")
                        {
                            config.NotificationsEnabled = psPropertyInfo.Value.ToString() == "False" ? false : true;
                            continue;
                        }
                        else if (psPropertyInfo.Name == "WriteBehindEnabled")
                        {
                            config.WriteBehindEnabled = psPropertyInfo.Value.ToString() == "True" ? true : false;
                            continue;
                        }
                        else if (psPropertyInfo.Name == "WriteBehindInterval")
                        {
                            config.WriteBehindInterval = psPropertyInfo.Value.ToString();
                            continue;
                        }
                        else if (psPropertyInfo.Name == "WriteBehindRetryInterval")
                        {
                            config.WriteBehindRetryInterval = psPropertyInfo.Value.ToString();
                            continue;
                        }
                        else if (psPropertyInfo.Name == "WriteBehindRetryCount")
                        {
                            config.WriteBehindRetryCount = psPropertyInfo.Value.ToString();
                            continue;
                        }
                        else if (psPropertyInfo.Name == "ReadThroughEnabled")
                        {
                            config.ReadThroughEnabled = psPropertyInfo.Value.ToString() == "True" ? true : false;
                            continue;
                        }
                        else if (psPropertyInfo.Name == "ProviderType")
                        {
                            config.ProviderType = psPropertyInfo.Value.ToString();
                            continue;
                        }
                        else if (psPropertyInfo.Name == "ProviderSettings")
                        {
                            config.ProviderSettings = (System.Collections.Hashtable)psPropertyInfo.Value;
                            continue;
                        }
                    }
                }
                return config;
            }
            return null;
        }

        public void StartCacheCluster()
        {
            Cluster.StartCluster clusterCommand = new Cluster.StartCluster();
            InvokeCommand(clusterCommand);
            GetCacheHosts();
        }

        public void StopCacheCluster()
        {
            Cluster.StopCluster clusterCommand = new Cluster.StopCluster();
            InvokeCommand(clusterCommand);
            GetCacheHosts();
        }

        public void RestartCacheCluster()
        {
            Cluster.RestartCluster clusterCommand = new Cluster.RestartCluster();
            InvokeCommand(clusterCommand);
            GetCacheHosts();
        }

        public void AddNewCache(Cache.NewCache _cacheConfig)
        {
            InvokeCommand(_cacheConfig);
            GetCache();
        }

        public void RemoveCache(String _cacheName)
        {
            Cache.RemoveCache cacheCommand = new Cache.RemoveCache();
            cacheCommand.Parameters["CacheName"] = _cacheName;
            InvokeCommand(cacheCommand);
            GetCache();
        }

        public CacheStatistics GetCacheStatistics(String _cacheName)
        {
            Cache.GetCacheStatistics cacheCommand = new Cache.GetCacheStatistics();
            cacheCommand.Parameters["CacheName"] = _cacheName;
            Collection<PSObject> results = InvokeCommand(cacheCommand);
            if (results != null)
            {
                CacheStatistics statistics = new CacheStatistics();
                statistics.CacheName = _cacheName;

                foreach (PSPropertyInfo psPropertyInfo in results[0].Properties)
                {
                    if (psPropertyInfo.Name == "Size")
                    {
                        statistics.Size = Convert.ToInt64(psPropertyInfo.Value);
                        continue;
                    }
                    if (psPropertyInfo.Name == "ItemCount")
                    {
                        statistics.ItemCount = Convert.ToInt64(psPropertyInfo.Value);
                        continue;
                    }
                    if (psPropertyInfo.Name == "RegionCount")
                    {
                        statistics.RegionCount = Convert.ToInt64(psPropertyInfo.Value);
                        continue;
                    }
                    if (psPropertyInfo.Name == "RequestCount")
                    {
                        statistics.RequestCount = Convert.ToInt64(psPropertyInfo.Value);
                        continue;
                    }
                    if (psPropertyInfo.Name == "ReadRequestCount")
                    {
                        statistics.ReadRequestCount = Convert.ToInt64(psPropertyInfo.Value);
                        continue;
                    }
                    if (psPropertyInfo.Name == "WriteRequestCount")
                    {
                        statistics.WriteRequestCount = Convert.ToInt64(psPropertyInfo.Value);
                        continue;
                    }
                    if (psPropertyInfo.Name == "MissCount")
                    {
                        statistics.MissCount = Convert.ToInt64(psPropertyInfo.Value);
                        continue;
                    }
                    if (psPropertyInfo.Name == "IncomimgBandwidth")
                    {
                        statistics.IncomimgBandwidth = Convert.ToInt64(psPropertyInfo.Value);
                        continue;
                    }
                    if (psPropertyInfo.Name == "OutgoingBandwidth")
                    {
                        statistics.OutgoingBandwidth = Convert.ToInt64(psPropertyInfo.Value);
                        continue;
                    }
                }
                return statistics;
            }
            return null;
        }

        public void ExportConfig(String _folderPath)
        {
            Cluster.ExportConfig clusterCommand = new Cluster.ExportConfig();
            clusterCommand.Parameters["File"] = _folderPath + "\\ClusterConfig.xml";
            InvokeCommand(clusterCommand);
        }

        public void ImportConfig(String _filePath)
        {
            Cluster.ImportConfig clusterCommand = new Cluster.ImportConfig();
            clusterCommand.Parameters["File"] = _filePath;
            InvokeCommand(clusterCommand);
        }

        public void StartHost(String _hostName, Int32 _port)
        {
            Host.StartCacheHost hostCommand = new Host.StartCacheHost();
            hostCommand.Parameters["HostName"] = _hostName;
            hostCommand.Parameters["CachePort"] = _port;
            InvokeCommand(hostCommand);
        }

        public void StopHost(String _hostName, Int32 _port, bool _graceful=false)
        {
            Host.StopCacheHost hostCommand = new Host.StopCacheHost();
            hostCommand.Parameters["HostName"] = _hostName;
            hostCommand.Parameters["CachePort"] = _port;
            if (_graceful)
                hostCommand.Parameters["Graceful"] = _graceful;
            InvokeCommand(hostCommand);
        }

        public void RestartHost(String _hostName, Int32 _port, bool _graceful=false)
        {
            Host.RestartCacheHost hostCommand = new Host.RestartCacheHost();
            hostCommand.Parameters["HostName"] = _hostName;
            hostCommand.Parameters["CachePort"] = _port;
            if (_graceful)
                hostCommand.Parameters["Graceful"] = _graceful;
            InvokeCommand(hostCommand);
        }


    }
}
